<?php

class Adept_Template_Expression_Factory 
{

    static protected $instance = null;
    
    protected $rules;
    protected $dictionary;
    
    protected function __construct()
    {
    	$this->rules = Adept_Template_Parser_Tpl_Rules::getInstance();
    	$this->dictionary = Adept_Template_Dictionary::getInstance();
    }
    
    static public function getInstance() 
    {
    	if (self::$instance == null) {
    		self::$instance = new self();
    	}
    	return self::$instance;
    }
    
    protected function createExpressionPart($string)
    {
        $constValueRule = $this->rules->getConstValueRule();
        
        if (preg_match("~^{$constValueRule}$~", $string)) {
            return new Adept_Template_Expression_Constant($string);
        } else {
            return new Adept_Template_Expression_DataBinding($string);
        }        
    }
    
    protected function parseModificator($name, $parametersString)
    {
        $info = $this->dictionary->getModificatorInfo($name);
        if ($info == null) {
            throw new Adept_Exception("Invalid modificator '{$name}'");
        }
        $class = $info->getClass();
        $modificator = new $class();
        $modificator->setInfo($info);
        
        $rule = $this->rules->getModificatorParameterRule(true);
        if (preg_match_all("~{$rule}~", $parametersString, $match)) {
            foreach ($match[1] as $parameter) {
                $modificator->addParameter($this->createExpressionPart($parameter));
            }
        }
        return $modificator;
        
    }
    
    public function createExpression($string)
    {
        $result = null;
        
    	$rule = $this->rules->getExpressionRule(true);
    	
    	if (preg_match("~^{$rule}$~", $string, $match)) {
    	    
    	    $base = $this->createExpressionPart($match[1]);
    	    $result = $base;
    	    
    	    if (!empty($match[2])) {
        	    $modRule = $this->rules->getModificatorRule(true);
        	    preg_match_all("~{$modRule}~", $match[2], $matches);        	    
        	    for ($i = 0; $i < count($matches[1]); $i++) {
        	        $modificator = $this->parseModificator($matches[1][$i], $matches[2][$i]);
        	        $modificator->setBase($result);
        	        $result = $modificator;
        	    }
    	    }
    	} else {
    	    throw new Adept_Exception('Cannot parse expression');
    	}
    	
    	return $result;
    }
    
}